﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using StreetlightGames.XnaEngine;

namespace StreetlightGames.SpaceShooter
{
    public class Starfield : DrawableGameComponent
    {
        private const int STAR_COUNT = 100;
        private const float MIN_DEPTH = 0.999f;
        private VertexPositionColor[] _stars;
        private VertexDeclaration _vertexDeclaration;
        private BasicEffect _basicEffect;

        /// <summary>Gets the SpaceShooterGame value</summary>
        public SpaceShooterGame SpaceShooterGame
        {
            get { return Game as SpaceShooterGame; }
        }
        
        public Starfield(Game game)
            : base(game)
        {
        }

        public override void Initialize()
        {
            _vertexDeclaration = new VertexDeclaration(Game.GraphicsDevice, VertexPositionColor.VertexElements);
            _basicEffect = new BasicEffect(Game.GraphicsDevice, null);
            _basicEffect.VertexColorEnabled = true;
            _basicEffect.World = Matrix.Identity;
            base.Initialize();
        }

        public override void Update(GameTime gameTime)
        {
            if (_stars == null)
            {
                Setup();
            }
            for (int i = 0; i < _stars.Length; i++)
            {
                _stars[i].Position.Z += (float)gameTime.ElapsedGameTime.TotalSeconds * 500;
                BoundingFrustum boundingFrustrum = SpaceShooterGame.Camera.BoundingFrustum;
                Vector3 farNormal = boundingFrustrum.Far.Normal;
                farNormal.Normalize();
                farNormal *= boundingFrustrum.Far.D;
                if (SpaceShooterGame.Camera.BoundingFrustum.Contains(_stars[i].Position) != ContainmentType.Contains)
                {
                    _stars[i].Position = Game.GraphicsDevice.Viewport.Unproject(
                        new Vector3(
                            RandomHelper.NextFloat(0, Game.GraphicsDevice.Viewport.Width),
                            0,
                            RandomHelper.NextFloat(MIN_DEPTH, Game.GraphicsDevice.Viewport.MaxDepth)),
                        SpaceShooterGame.Camera.ProjectionMatrix,
                        SpaceShooterGame.Camera.ViewMatrix,
                        Matrix.Identity);
                }
            }
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            _basicEffect.View = SpaceShooterGame.Camera.ViewMatrix;
            _basicEffect.Projection = SpaceShooterGame.Camera.ProjectionMatrix;

            Game.GraphicsDevice.VertexDeclaration = _vertexDeclaration;

            _basicEffect.Begin();

            foreach (EffectPass pass in _basicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                Game.GraphicsDevice.RenderState.PointSize = 1;
                Game.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                    PrimitiveType.PointList,
                    _stars,
                    0,
                    STAR_COUNT);
                pass.End();
            }

            _basicEffect.End();
            base.Draw(gameTime);
        }

        private void Setup()
        {
            _stars = new VertexPositionColor[STAR_COUNT];
            for (int i = 0; i < STAR_COUNT; i++)
            {
                Vector3 position = new Vector3(
                            RandomHelper.NextFloat(0, Game.GraphicsDevice.Viewport.Width),
                            RandomHelper.NextFloat(0, Game.GraphicsDevice.Viewport.Height),
                            RandomHelper.NextFloat(MIN_DEPTH, Game.GraphicsDevice.Viewport.MaxDepth));
                _stars[i] = new VertexPositionColor(
                    Game.GraphicsDevice.Viewport.Unproject(
                            position,
                            SpaceShooterGame.Camera.ProjectionMatrix,
                            SpaceShooterGame.Camera.ViewMatrix,
                            Matrix.Identity),
                    Color.White);
            }
            base.LoadContent();
        }
    }
}
